malloc like rust feature

struct List<T> {
	head: *mut Node<T>,
	tail: *mut Node<T>,
}
struct Node<T> {
	elem: T,
	next: *mut Node<T>,
}
//...
pub fn push(&mut self, elem: T) {
	let new_tail = Node { elem, next: std::ptr::null_mut() };
	// ...
}

이렇게 쓰면 코딩인생 망함. Node를 생성하는 블럭을 벗어나면 new_tail에 대한 데이터가 drop이 되는데 거기에 연결된 headtail이나 전부 dangling pointer가 되는 것이다! 얏호!

어쨌든 결국 힙영역에 메모리를 요청해야 하고, Box의 도움을 받아야 한다.

impl List<T> {
pub fn push(&mut self, elem: T) {
	let new_tail = Box::new(Node {elem, next: std::ptr::null_ptr() };
	self.head = ???
	self.tail = ???
}
}

그런데 Box 타입은 필요 이상으로 안전하다. 따라서 이걸 포인터로 바꿔주어야 한다. 이때 사용하는 방법이 바로 Box::into_raw() 이다.

let new_tail = Box::into_raw(
	Box::new(
		Node { elem, std::ptr::null_mut() }
	));

이게뭔 malloc같은 소리인지 모르겠는데, 러스트에선 이렇게 써야 한다...

마지막으로 해당 타입을 drop 하거나 move할 필요가 있을 땐 포인터를 deref만 하면 안된다! 반드시 Box로 다시 래핑하여서 객체를 줘야만 한다.

// Re-wrap into Box
let ret = Box::from_raw(self.head);

self.head = ret.next;

if self.head.is_null() {
	// empty tail again!
	self.tail = null_mut();
}

Some(ret.elem)